속성

  • Object.prototype

모든 객체는 Object.prototype으로부터 메소드 및 속성을 상속, 모든 객체를 만들면, 해당 속성/메서드가 상속되어 있다.

다음 코드를 보자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var person = {
name : "child of earth",
age : 0,
nature : "cool",
eat : function() {
alert(this.name + "is eating");
}
}

var narendra = Object.create(person);
narendra.name = "Narendra Sisdoiya";
narendra.age = 29;
narendra.eat();

narendra.hasOwnProperty("eat"); // false
narendra.hasOwnProperty("name"); // true
narendra.hasOwnPropery("nature"); // false

object prototype에 대한 이미지 검색결과

내장 객체인 Object와, Object.prototype이 있다.

자세한 내용은 상속과 prototype 포스팅 참조

  • Object.prototype.constructor

객체의 프로토타입을 생성하는 함수, 객체의 타입을 파악하는데 쓰이지만, instance of 연산자가 더 안전하다.

1
2
3
4
5
6
7
8
9
var o = {};
o.constructor === Object; // true
o instanceof Object // true

var a = [];
a.constructor === Array; // true

var n = new Number(3);
n.constructor === Number; // true
  • Object.prototype.__proto__

객체가 초기화될 때 프로토타입으로 사용된 객체, 즉 상속받은 내용들이 들어있다.

1
2
3
var a = {};
a.__proto__ === Object; // false
a.__proto__ === Object.prototype; // true

메서드

  • Object.hasOwnPropery()

상속받지 않은, 순수한 자신의 프로퍼티 여부를 확인한다.

1
2
3
4
5
o = new Object();
o.prop = 'exists';
o.hasOwnProperty('prop'); // returns true
o.hasOwnProperty('toString'); // returns false
o.hasOwnProperty('hasOwnProperty'); // returns false
  • Object.create()

constructor 깨짐 없이 깔끔하게, prototype을 적용하여 객체를 생성한다. 아래와 같은 로직과 일치한다. 이때 넘겨준 객체 o는 prototype의 원리와 같이 객체를 공유하게 된다.

1
2
3
4
5
function object(o) {
function F() {}
F.prototype = o;
return new F();
}

Object.create(프로토타입이 될 객체, 추가할 프로퍼티 객체)

1
2
3
4
5
6
7
var person = { name: "hi", friends : ["hi", "ho"] }
// p1, p2는 person 객체를 공유하게 된다.
var p1 = Object.create(person);
var p2 = Object.create(person);

var p3 = Object.create(person, { name : { value : "Gre"} })
// 두번째 파라미터는 Object.defineProperties와 유사하다.

생성자 함수를 만들어 create를 사용할 경우

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Shape - 상위클래스
function Shape() {
this.x = 0;
this.y = 0;
}

// 상위클래스 메서드
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('Shape moved.');
};

// Rectangle - 하위클래스
function Rectangle() {
Shape.call(this); // super 생성자 호출.
}

// 하위클래스는 상위클래스를 확장
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

console.log('Is rect an instance of Rectangle?', rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?', rect instanceof Shape); // true
rect.move(1, 1); // Outputs, 'Shape moved.'
  1. Object.create(Shape.prototype) : create의 인자로 프로토타입으로 쓰일 객체를 넘겨줘야 한다.
  2. Shape.call(this) : 상속 포스팅에도 설명했듯이, Shape의 this인자들을 Rectangle 컨텍스트에서 생성하게 하여 자신의 프로퍼티를 가지게 된다.
  • Object.defineProperties()

데이터 프로퍼티와, 접근자 프로퍼티 를 셋팅한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var obj = {};
Object.defineProperties(obj, {
'_x': {
value: 0,
writable: true
},
'x': {
get: function() {
return this._x;
},
set: function(newValue) {
this._x = newValue+1;
}
},
'_y': { ... }
});

configurable, enumerable 와 같은 속성을 설정하지 않으면 default로 false가 할당된다.

언제 사용할까?

1
2
3
4
5
6
7
8
9
10
// defineProperties 사용하지 않을때
Object.prototype.imFunc = function() {
console.log('aa');
}

var a = new Object();
for(var b in a) {
console.log(b);
}
// 결과 : imFunc

for in문에서 순회하고 싶지 않아도, 함수가 나온다. 이때 사용해보자

1
2
3
4
5
6
7
8
9
10
11
12
13
Object.defineProperty(Object.prototype, 'imFunc', {
enumerable: false,
configurable: false,
writable: false,
value: function() {
console.log('aa');
}
});

for(var b in a) {
console.log(b);
}
// imFunc가 순회되지 않는다!
  • Object.getOwnPropertyDescriptor()

접근자/데이터 프로퍼티 객체를 읽어온다.

1
2
3
4
5
// 위 예제에서 이어짐
var descriptor = Object.getOwnPropertyDescriptor(obj, "_x");
alert(descriptor.value); // 0
alert(descriptor.configurable); // false
alert(descriptor.get);
  • Object.preventExtensions(), Object.isExtensible()

새로운 프로퍼티를 추가할 수 없도록한다. 값 수정은 가능.

  • Object.seal(), Object.isSealed()

새로운 프로퍼티를 추가할 수 없도록한다. 값 수정은 가능하지만, configurable 값은 false로 바꾼다.

  • Object.getOwnPropertyNames()

파라미터 : object

리턴 : 문자열 배열

1
2
3
4
5
6
7
8
var arr = ['a', 'b', 'c'];
console.log(Object.getOwnPropertyNames(arr).sort());
// logs ["0", "1", "2", "length"]

// Array-like object
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.getOwnPropertyNames(obj).sort());
// logs ["0", "1", "2"]
  • Object.getPrototypeOf()

prototype을 리턴한다.

1
2
3
4
Object.getPrototypeOf('foo');
// TypeError: "foo" is not an object (ES5 code)
Object.getPrototypeOf('foo');
// String.prototype (ES2015 code)

ES6

  • Object.assign()

Object 병합하기

파라미터 : 타겟, 소스

1
2
3
4
5
6
7
var o1 = { a: 1 };
var o2 = { a: 1, b: 2 };
var o3 = { c: 3 };

var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, 타겟 오브젝트, 그 자체도 변화합니다.
  • Object.freeze()

객체를 읽기전용으로 바꾼다. 프로퍼티 추가/삭제/변경, 이나 enumerability, configyrability 등의 속성 변경 또한 막는다.

ES8

  • Object.entries()

열거 가능한 객체를 [key, value] 배열로 만들어 리턴함

파라미터 : key, value 쌍의 객체

리턴 : key, value 쌍의 배열

1
2
3
4
5
6
7
8
9
10
11
12
var obj = { foo: 'bar', baz: 42 };
console.log(Object.entries(obj));
// [ ['foo', 'bar'], ['baz', 42] ]

var obj = {a: 5, b: 7, c: 9};
for (var [key, value] of Object.entries(obj)) {
console.log(key + ' ' + value); // "a 5", "b 7", "c 9"
}

Object.entries(obj).forEach(([key, value]) => {
console.log(key + ' ' + value); // "a 5", "b 7", "c 9"
});

Reference

https://medium.com/@bluesh55/javascript-prototype-이해하기-f8e67c286b67

http://unikys.tistory.com/320

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/